<script setup>
import { ref, onMounted } from 'vue'
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import 'ol/ol.css'
import Draw from 'ol/interaction/Draw'
import Modify from 'ol/interaction/Modify'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import CircleStyle from 'ol/style/Circle'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'
import Style from 'ol/style/Style'
import LineString from 'ol/geom/LineString'
import Polygon from 'ol/geom/Polygon'
import { getLength, getArea } from 'ol/sphere'
import { unByKey } from 'ol/Observable'
import Overlay from 'ol/Overlay'

const mapRef = ref(null)
const map = ref(null)

// 测量相关变量
const measureSource = new VectorSource()
const measureVector = new VectorLayer({
  source: measureSource,
  style: new Style({
    fill: new Fill({
      color: 'rgba(255, 255, 255, 0.2)'
    }),
    stroke: new Stroke({
      color: '#ffcc33',
      width: 2
    }),
    image: new CircleStyle({
      radius: 7,
      fill: new Fill({
        color: '#ffcc33'
      })
    })
  })
})

const sketch = ref(null)
const helpTooltipElement = ref(null)
const helpTooltip = ref(null)
const measureTooltipElement = ref(null)
const measureTooltip = ref(null)
const draw = ref(null)
const listener = ref(null)

// 右键菜单相关变量
const contextMenuVisible = ref(false)
const contextMenuPosition = ref({ x: 0, y: 0 })

// 当前测量模式
const measureMode = ref(null) // 'length' 或 'area'

// 格式化长度
const formatLength = (line) => {
  // 使用WGS84球体计算距离，提高精度
  const length = getLength(line, {
    projection: 'EPSG:4326',
    radius: 6378137 // 地球半径（米）
  })
  
  // 基本单位改为km
  const lengthInKm = length / 1000
  
  // 根据距离大小决定显示精度
  let output
  if (lengthInKm >= 100) {
    // 大于100km，显示整数
    output = Math.round(lengthInKm) + ' km'
  } else if (lengthInKm >= 1) {
    // 1-100km，显示两位小数
    output = Math.round(lengthInKm * 100) / 100 + ' km'
  } else {
    // 小于1km，显示三位小数
    output = Math.round(lengthInKm * 1000) / 1000 + ' km'
  }
  return output
}

// 格式化面积
const formatArea = (polygon) => {
  // 使用WGS84球体计算面积，提高精度
  const area = getArea(polygon, {
    projection: 'EPSG:4326',
    radius: 6378137 // 地球半径（米）
  })
  
  // 基本单位改为km²
  const areaInKm2 = area / 1000000
  
  // 根据面积大小决定显示精度
  let output
  if (areaInKm2 >= 100) {
    // 大于100km²，显示整数
    output = Math.round(areaInKm2) + ' km²'
  } else if (areaInKm2 >= 1) {
    // 1-100km²，显示两位小数
    output = Math.round(areaInKm2 * 100) / 100 + ' km²'
  } else {
    // 小于1km²，显示四位小数
    output = Math.round(areaInKm2 * 10000) / 10000 + ' km²'
  }
  return output
}

// 创建帮助提示
const createHelpTooltip = () => {
  if (helpTooltipElement.value) {
    helpTooltipElement.value.parentNode.removeChild(helpTooltipElement.value)
  }
  helpTooltipElement.value = document.createElement('div')
  helpTooltipElement.value.className = 'ol-tooltip hidden'
  helpTooltip.value = new Overlay({
    element: helpTooltipElement.value,
    offset: [15, 0],
    positioning: 'center-left'
  })
  map.value.addOverlay(helpTooltip.value)
}

// 创建测量提示
const createMeasureTooltip = () => {
  if (measureTooltipElement.value) {
    measureTooltipElement.value.parentNode.removeChild(measureTooltipElement.value)
  }
  measureTooltipElement.value = document.createElement('div')
  measureTooltipElement.value.className = 'ol-tooltip ol-tooltip-measure'
  measureTooltip.value = new Overlay({
    element: measureTooltipElement.value,
    offset: [0, -15],
    positioning: 'bottom-center'
  })
  map.value.addOverlay(measureTooltip.value)
}

// 开始测量
const startMeasure = (type) => {
  // 清除之前的测量
  if (draw.value) {
    map.value.removeInteraction(draw.value)
  }
  
  // 设置测量模式
  measureMode.value = type
  
  // 创建测量交互
  draw.value = new Draw({
    source: measureSource,
    type: type === 'length' ? 'LineString' : 'Polygon',
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 255, 255, 0.2)'
      }),
      stroke: new Stroke({
        color: 'rgba(0, 0, 0, 0.5)',
        lineDash: [10, 10],
        width: 2
      }),
      image: new CircleStyle({
        radius: 5,
        stroke: new Stroke({
          color: 'rgba(0, 0, 0, 0.7)'
        }),
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.2)'
        })
      })
    })
  })
  
  map.value.addInteraction(draw.value)
  
  createMeasureTooltip()
  createHelpTooltip()
  
  let listener
  draw.value.on('drawstart', (evt) => {
    sketch.value = evt.feature
    
    let tooltipCoord = evt.coordinate
    
    listener = sketch.value.getGeometry().on('change', (evt) => {
      const geom = evt.target
      let output
      if (geom instanceof LineString) {
        output = formatLength(geom)
        tooltipCoord = geom.getLastCoordinate()
      } else if (geom instanceof Polygon) {
        output = formatArea(geom)
        tooltipCoord = geom.getInteriorPoint().getCoordinates()
      }
      measureTooltipElement.value.innerHTML = output
      measureTooltip.value.setPosition(tooltipCoord)
    })
  })
  
  draw.value.on('drawend', () => {
    measureTooltipElement.value.className = 'ol-tooltip ol-tooltip-static'
    measureTooltip.value.setOffset([0, -7])
    sketch.value = null
    measureTooltipElement.value = null
    createMeasureTooltip()
    unByKey(listener)
  })
}

// 停止测量
const stopMeasure = () => {
  if (draw.value) {
    map.value.removeInteraction(draw.value)
    draw.value = null
  }
  measureMode.value = null
}

// 显示右键菜单
const showContextMenu = (event) => {
  event.preventDefault()
  contextMenuVisible.value = true
  contextMenuPosition.value = {
    x: event.clientX,
    y: event.clientY
  }
}

// 隐藏右键菜单
const hideContextMenu = () => {
  contextMenuVisible.value = false
}

// 处理右键菜单选择
const handleContextMenuSelect = (type) => {
  hideContextMenu()
  startMeasure(type)
}

// 清空测量结果
const clearMeasurements = () => {
  // 清除所有测量图形
  measureSource.clear()
  
  // 移除所有测量提示
  const overlays = map.value.getOverlays()
  const overlaysToRemove = []
  
  overlays.forEach(overlay => {
    const element = overlay.getElement()
    if (element && (
      element.className === 'ol-tooltip ol-tooltip-static' || 
      element.className === 'ol-tooltip ol-tooltip-measure'
    )) {
      overlaysToRemove.push(overlay)
    }
  })
  
  overlaysToRemove.forEach(overlay => {
    map.value.removeOverlay(overlay)
  })
  
  // 停止当前测量
  stopMeasure()
}

onMounted(() => {
  // 初始化地图
  map.value = new Map({
    target: mapRef.value,
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
          crossOrigin: 'anonymous'
        })
      }),
      measureVector // 添加测量图层
    ],
    view: new View({
      center: [104, 35], // 地图中心坐标（经度，纬度）- 设置为中国中心
      zoom: 5,         // 初始缩放级别
      projection: 'EPSG:4326' // 使用WGS84坐标系
    })
  })
  
  // 添加右键菜单事件监听
  const mapElement = mapRef.value
  mapElement.addEventListener('contextmenu', showContextMenu)
  
  // 点击地图其他区域隐藏右键菜单
  mapElement.addEventListener('click', hideContextMenu)
  // 显示提示弹窗
  alert('鼠标右键开始测量');
})
</script>

<template>
  <div class="map-container">
    <div class="measure-status" v-if="measureMode">
      当前模式: {{ measureMode === 'length' ? '测距' : '测面积' }}
      <button @click="stopMeasure" class="stop-button">停止测量</button>
      <button @click="clearMeasurements" class="clear-button">清空结果</button>
    </div>
    <div class="clear-measurements" v-else>
      <button @click="clearMeasurements" class="clear-button">清空测量结果</button>
    </div>
    <div ref="mapRef" class="map"></div>
    
    <!-- 右键菜单 -->
    <div 
      class="context-menu" 
      v-if="contextMenuVisible" 
      :style="{ left: contextMenuPosition.x + 'px', top: contextMenuPosition.y + 'px' }"
    >
      <div class="menu-item" @click="handleContextMenuSelect('length')">
        测量距离
      </div>
      <div class="menu-item" @click="handleContextMenuSelect('area')">
        测量面积
      </div>
    </div>
  </div>
</template>

<style scoped>
.map-container {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
}

h1 {
  margin: 20px 0;
  color: #333;
}

.map {
  width: 90%;
  height: 80vh;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

/* 测量状态样式 */
.measure-status {
  position: absolute;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(255, 255, 255, 0.9);
  padding: 8px 15px;
  border-radius: 4px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 10px;
}

.stop-button {
  background-color: #ff4d4f;
  color: white;
  border: none;
  border-radius: 4px;
  padding: 5px 10px;
  cursor: pointer;
  font-size: 14px;
}

.stop-button:hover {
  background-color: #ff7875;
}

.clear-button {
  background-color: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  padding: 5px 10px;
  cursor: pointer;
  font-size: 14px;
  margin-left: 10px;
}

.clear-button:hover {
  background-color: #40a9ff;
}

.clear-measurements {
  position: absolute;
  top: 70px;
  right: 5%;
  background-color: rgba(255, 255, 255, 0.9);
  padding: 8px 15px;
  border-radius: 4px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  z-index: 1000;
}

/* 右键菜单样式 */
.context-menu {
  position: fixed;
  background-color: white;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  min-width: 150px;
}

.menu-item {
  padding: 10px 15px;
  cursor: pointer;
  border-bottom: 1px solid #eee;
}

.menu-item:last-child {
  border-bottom: none;
}

.menu-item:hover {
  background-color: #f5f5f5;
}

/* 测量提示样式 */
:deep(.ol-tooltip) {
  position: relative;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  white-space: nowrap;
  font-size: 12px;
  cursor: default;
  user-select: none;
}

:deep(.ol-tooltip-measure) {
  background: rgba(255, 255, 255, 0.7);
  color: black;
  border: 1px solid #ccc;
  border-radius: 4px;
}

:deep(.ol-tooltip-static) {
  background-color: #ffcc33;
  color: black;
  border: 1px solid white;
}

:deep(.ol-tooltip-measure:before),
:deep(.ol-tooltip-static:before) {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

:deep(.ol-tooltip-static:before) {
  border-top-color: #ffcc33;
}
:deep(.ol-tooltip-measure:before),
:deep(.ol-tooltip-static:before) {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

:deep(.ol-tooltip-static:before) {
  border-top-color: #ffcc33;
}
</style>

